﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using System.Globalization;
using Microsoft.Win32;
using System.ServiceProcess;
using Microsoft.SharePoint.Administration;
using System.IO;
using System.Collections;
using Microsoft.SharePoint.Utilities;
using System.Reflection;
using System.Collections.ObjectModel;
using SPALM.MSBuildTasks;
using System.ComponentModel;

namespace SPALM
{
  /// <summary>
  /// Deployment operations for deployment of farm and sandboxed solutions
  /// </summary>
  [Category("Deployment Operations")]
  [Description("Deployment operations for deployment of farm and sandboxed solutions")]
  public class Deployment : CoreTask
  {
    public Deployment()
      : base()
    {
      this.Overwrite = true;
      this.Force = true;
      this.Retries = 3;
      this.SimulateDeployment = false;
      this.WaitMilliSecondsAfterFinish = 0;
    }

    private const string ConstAddAndDeploySolutions = "AddAndDeploySolutions";
    private const string ConstRetractAndDeleteSolutions = "RetractAndDeleteSolutions";

    private const string ConstUpgradeSolutions = "UpgradeSolutions";
    private const string ConstUpgradeSandboxedSolutions = "UpgradeSandboxedSolutions";

    private const string ConstAddAndDeploySandboxedSolutions = "AddAndDeploySandboxedSolutions";
    private const string ConstRetractAndDeleteSandboxedSolutions = "RetractAndDeleteSandboxedSolutions";

    private const string ConstRestartSPTimer = "RestartSPTimer";
    private const string ConstRestartSPAdmin = "RestartSPAdmin";
    private const string ConstRestartSPUserCodeHost = "RestartSPUserCodeHost";
    private const string ConstRestartIIS = "RestartIIS";

    [DropdownValue(ConstAddAndDeploySolutions)]
    [DropdownValue(ConstRetractAndDeleteSolutions)]
    [DropdownValue(ConstUpgradeSolutions)]
    [DropdownValue(ConstUpgradeSandboxedSolutions)]
    [DropdownValue(ConstAddAndDeploySandboxedSolutions)]
    [DropdownValue(ConstRetractAndDeleteSandboxedSolutions)]
    [DropdownValue(ConstRestartSPTimer)]
    [DropdownValue(ConstRestartSPAdmin)]
    [DropdownValue(ConstRestartSPUserCodeHost)]
    [DropdownValue(ConstRestartIIS)]
    public override string TaskAction
    {
      get { return base.TaskAction; }
      set { base.TaskAction = value; }
    }

    #region properties

    /// <summary>
    /// URLs of all web application, separated by semicolon, for the deployment operation of farm solutions
    /// </summary>
    [TaskAction(ConstAddAndDeploySolutions, false)]
    [TaskAction(ConstUpgradeSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [Description("URLs of all web application, separated by semicolon, for the deployment operation of farm solutions")]
    public string WebApplications { get; set; }

    /// <summary>
    /// URLs of all site collection, separated by semiconon, for the deployment operation of sandboxed solutions
    /// </summary>
    [TaskAction(ConstAddAndDeploySandboxedSolutions, false)]
    [TaskAction(ConstUpgradeSandboxedSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [Description("URLs of all site collection, separated by semiconon, for the deployment operation of sandboxed solutions")]
    public string Sites { get; set; }

    /// <summary>
    /// URLs of all site collection, separated by semiconon, for the deployment operation of sandboxed solutions
    /// </summary>
    [TaskAction(ConstAddAndDeploySolutions, false)]
    [Description("True, to deploy farm solutions to all content urls")]
    public bool AllContentUrls { get; set; }

    [TaskAction(ConstAddAndDeploySolutions, false)]
    [Description("True, to force the deployment of farm solutions")]
    public bool Force { get; set; }

    /// <summary>
    /// Number of retries for the operation
    /// </summary>
    [TaskAction(ConstAddAndDeploySolutions, false)]
    [TaskAction(ConstUpgradeSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [Description("Number of retries for the operation")]
    public int Retries { get; set; }

    /// <summary>
    /// Number of milliseconds to wait of the finish of the deployment operation
    /// </summary>  
    [TaskAction(ConstAddAndDeploySolutions, false)]
    [TaskAction(ConstUpgradeSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [TaskAction(ConstAddAndDeploySandboxedSolutions, false)]
    [TaskAction(ConstUpgradeSandboxedSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [Description("Number of retries for the operation")]
    public int WaitMilliSecondsAfterFinish { get; set; }

    public bool SimulateDeployment { get; set; }

    [TaskAction(ConstAddAndDeploySandboxedSolutions, false)]
    [TaskAction(ConstAddAndDeploySolutions, false)]
    [Description("True to retract existing solution before adding new solution")]
    public bool Overwrite { get; set; }

    [TaskAction(ConstAddAndDeploySolutions, false)]
    [Description("True to retract existing solution before adding new solution")]
    public bool AllowGACDeployment { get; set; }

    [TaskAction(ConstAddAndDeploySolutions, false)]
    [Description("True to allow CAS policies for deployment operation")]
    public bool AllowCASPolicies { get; set; }

    [TaskAction(ConstAddAndDeploySolutions, false)]
    [TaskAction(ConstUpgradeSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [TaskAction(ConstAddAndDeploySandboxedSolutions, false)]
    [TaskAction(ConstUpgradeSandboxedSolutions, false)]
    [TaskAction(ConstRetractAndDeleteSolutions, false)]
    [Description("Path to WSP solution files, separated by semicolon for the deployment operation")]
    public override string Solutions { get; set; }

    #endregion

    public override bool Execute()
    {
      switch (this.TaskAction)
      {
        case ConstAddAndDeploySolutions:
          return AddAndDeploySolutions();
        case ConstRetractAndDeleteSolutions:
          return RetractAndDeleteSolutions();
        case ConstUpgradeSolutions:
          return UpgradeSolutions();
        case ConstUpgradeSandboxedSolutions:
          return UpgradeSandboxedSolutions();
        case ConstAddAndDeploySandboxedSolutions:
          return AddAndDeploySandboxedSolutions();
        case ConstRetractAndDeleteSandboxedSolutions:
          return new RetractAndDeleteSandboxedSolutionsOperation(this, Solutions, Sites, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
        case ConstRestartSPTimer:
          return RestartSPTimer();
        case ConstRestartSPAdmin:
          return RestartSPAdmin();
        case ConstRestartSPUserCodeHost:
          return RestartSPUserCodeHost();
        case ConstRestartIIS:
          return RestartIIS();
        default:
          Log.LogError(string.Format(CultureInfo.CurrentCulture, "Invalid TaskAction passed: {0}", this.TaskAction));
          return false;
      }
      return false;
    }

    [Description("Restarts the IIS service")]
    private bool RestartIIS()
    {
      return new RestartIIS(this, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Restarts the SPUserCodeHost service")]
    private bool RestartSPUserCodeHost()
    {
      return new RestartSPUserCodeHost(this, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Restarts the SPAdmin service")]
    private bool RestartSPAdmin()
    {
      return new RestartSPAdmin(this, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Restarts the SPTimer service")]
    private bool RestartSPTimer()
    {
      return new RestartSPTimer(this, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Upgrade the given sandboxed solutions")]
    private bool UpgradeSandboxedSolutions()
    {
      new RetractAndDeleteSandboxedSolutionsOperation(this, Solutions, Sites, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
      return new AddAndDeploySandboxedSolutionsOperation(this, Solutions, Sites, true, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Adds and activates the given sandboxed solutions")]
    private bool AddAndDeploySandboxedSolutions()
    {
      return new AddAndDeploySandboxedSolutionsOperation(this, Solutions, Sites, Overwrite, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Upgrade the given farm solutions")]
    private bool UpgradeSolutions()
    {
      return new UpgradeSolutionsOperation(this, Solutions, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Retracts and deletes the given farm solutions")]
    private bool RetractAndDeleteSolutions()
    {
      return new RetractAndDeleteSolutionsOperation(this, Solutions, WebApplications, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }

    [Description("Adds and deploys the given farm solutions")]
    private bool AddAndDeploySolutions()
    {
      return new AddAndDeploySolutionsOperation(this, Solutions, WebApplications, AllContentUrls, Force, AllowGACDeployment, AllowCASPolicies, Overwrite, Retries, WaitMilliSecondsAfterFinish, SimulateDeployment).Run();
    }
  }
}

